每个楼房,还有单点修改操作。简单的想到用线段树来维护信息。
显然线段树只需要维护y/x即可,对于每一个楼房,能看见的条件就是前面楼房的y/x的严格小于当前楼房的y/x。
线段树的区间修改不再赘述。
那么怎么维护可以看到的楼房数呢?
考虑在线段树的每一个节点上用一个变量sum
来表示从这个节点的左端点向右端点看时能看到多少楼房。
假设现在有一区间:1,5,8,0,7,9
。维护这个区间信息的节点编号为x
。
x的左儿子维护的区间是1,5,8
,从1
往8
看可以看到三个楼房,故x的左儿子的sum的值为3
。
x的右儿子维护的区间是0,7,9
,从0
往9
看也可以看到三个楼房,故x的右儿子的sum的值也为3
。
难道x的sum值
也为3+3=6
?错!
这显然是不能加在一起的,x的sum的值
为4。
为什么会错呢?因为x的右儿子的观察视角不是从1开始的,是从0开始的。
显然0被前面的楼房挡住了。
首先考虑每个线段树节点在维护一个mx
,mx
代表这个节点所代表的区间中所有的楼房中最高的高度。
上传时,由于两个儿子的sum
值是已经处理好的,而左儿子的视角是跟x
的视角一样的(对于上面的例子来说都是1),可以直接上传,即sum(x)+=sum(l(x))
。
对于右儿子,考虑递归处理右儿子的区间,递归时带一个Mx
变量表示x的左儿子mx
(右儿子再左儿子后面,原因下面解释),递归函数的返回值是当前处理区间可以被看到的楼房数(从x的视角看)
对于现在处理的每一个区间:
- 如果这个区间的最高的楼房的高度都Mx(可以看到),那么return 当前区间维护的sum值。
- 如果这个区间只代表一个楼房,直接判断其能否被看到即可。
- 对于剩下的情况,递归儿子,分两种情况讨论:
- 如果左儿子的最高的楼房小于Mx(不能对答案有任何贡献),直接递归右儿子。
- 否则,递归左儿子,右儿子能看到的楼房个数为当前区间sum-左儿子sum即可,(应为下面已经更新好了,只需要直接调用就好了。)
Code(文中的sum用l代替):
1 |
|
文章作者:Qiuly
发布时间:2019年02月13日 - 00:00
最后更新:2019年03月29日 - 13:52
原始链接:http://qiulyblog.github.io/2019/02/13/[题解]bzoj2957/
许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。